package com.learn.ThreadPoolLearn;

import org.apache.log4j.Logger;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author ln
 * @Description: ${todo}
 * @date 2020/12/23
 */
public class TestPool {
    private static final Logger log = Logger.getLogger(TestPool.class);

    public static void main(String[] args) {
        ThreadPool threadPool = new ThreadPool(2, 1000, TimeUnit.MILLISECONDS, 10,(queue,task)->{
//            1.死等
//            queue.put(task);
//            2）带超时等待
//            queue.offer(task,500,TimeUnit.MILLISECONDS);
//            3）放弃任务执行
//            log.debug("放弃任务"+task);
//            4）抛出异常
//            throw new RuntimeException(task+"任务执行失败");
//            5）让调用者自己执行任务
            task.run();
        });
        for (int i = 0; i < 5; i++) {
            int j = i;
            threadPool.execute(() -> {
                log.debug("j是" + j);
            });
        }
    }

}

//拒绝策略
@FunctionalInterface
interface RejectPolicy<T> {
    void reject(BlockingQueue<T> queue, T task);
}

class ThreadPool {
    //    任务队列
    private BlockingQueue<Runnable> taskQueue;

    //    线程集合
    private HashSet<Worker> workers = new HashSet<>();

    //    核心线程数
    private int coreSize;

    //    任务的超时时间
    private long timeout;
    //    时间单位
    private TimeUnit timeUnit;

    private RejectPolicy<Runnable> rejectPolicy;


    public ThreadPool(int coreSize, long timeout, TimeUnit timeUnit, int queueCapcity, RejectPolicy<Runnable> rejectPolicy) {
        this.coreSize = coreSize;
        this.timeout = timeout;
        this.timeUnit = timeUnit;
        this.taskQueue = new BlockingQueue<>(queueCapcity);
        this.rejectPolicy = rejectPolicy;
    }

    //    执行任务
    public void execute(Runnable task) {
//        当任务数没有超过coreSize时，直接交给Worker的对象处理
//        如果任务数超过了coreSize时，加入任务队列暂存
        synchronized (workers) {
            if (workers.size() < coreSize) {
                Worker worker = new Worker(task);
                workers.add(worker);
                worker.start();
            } else {
//                taskQueue.put(task);//死等
//                1)死等
//                2）带超时等待
//                3）放弃任务执行
//                4）抛出异常
//                5）让调用者自己执行任务
                taskQueue.tryput(rejectPolicy, task);
            }
        }
    }

    class Worker extends Thread {
        private final Logger log = Logger.getLogger(Worker.class);

        private Runnable task;

        public Worker(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
//            执行任务
//            1）当task不为空，执行任务
//            2）当task执行完毕，再接着从任务队列获取任务并执行
//            while (task!=null || (task=taskQueue.take())!=null){
            while (task != null || (task = taskQueue.poll(timeout, timeUnit)) != null) {
                try {
                    task.run();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    task = null;
                }
            }
            synchronized (workers) {
                log.debug("work被移除" + this);
                workers.remove(this);
            }
        }
    }
}
//ThreadPool结束

class BlockingQueue<T> {
    //    1.任务队列,双向链表
    private Deque<T> queue = new ArrayDeque<>(); //ArrayDeque比ArrayList的效率要高

    //    2.锁
    private ReentrantLock lock = new ReentrantLock();

    //    3.生产者条件变量
    private Condition fullWaitSet = lock.newCondition();


    //    4.消费者条件变量
    private Condition emptyWaitSet = lock.newCondition();

    //    5.队列容量
    private int capcity;

    public BlockingQueue(int capcity) {
        this.capcity = capcity;
    }

    //    带超时的阻塞获取
    public T poll(long timeout, TimeUnit timeUnit) {
        lock.lock();
        try {
//            将timeout统一转化为纳秒
            long nanos = timeUnit.toNanos(timeout);
            while (queue.isEmpty()) {
                try {
                    if (nanos <= 0) {//说明超时了，就不需要等待了
                        return null;
                    }
//                    返回的是剩余时间
                    nanos = emptyWaitSet.awaitNanos(nanos);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            T t = queue.removeFirst();
            fullWaitSet.signal();
            return t;
        } finally {
            lock.unlock();
        }
    }


    //    阻塞获取
    public T take() {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                try {
                    emptyWaitSet.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            T t = queue.removeFirst();
            fullWaitSet.signal();
            return t;
        } finally {
            lock.unlock();
        }

    }

    //    阻塞添加
    public void put(T task) {
        lock.lock();
        try {
            while (queue.size() == capcity) {
                try {
                    fullWaitSet.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue.addLast(task);
            emptyWaitSet.signal();
        } finally {
            lock.unlock();
        }

    }

    //    带超时时间的阻塞添加
    public boolean offer(T task, long timeout, TimeUnit timeUnit) {
        lock.lock();
        try {
            long nanos = timeUnit.toNanos(timeout);
            while (queue.size() == capcity) {
                try {
                    if (nanos <= 0) {//超时
                        return false;
                    }
                    nanos = fullWaitSet.awaitNanos(nanos);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue.addLast(task);
            emptyWaitSet.signal();
            return true;
        } finally {
            lock.unlock();
        }
    }


    //    获取大小
    public int getsize() {
        lock.lock();
        try {
            return queue.size();
        } finally {
            lock.unlock();
        }
    }

    public void tryput(RejectPolicy<T> rejectPolicy, T task) {
        lock.lock();
        try {
//            判断队列是否满
            if (queue.size() == capcity) {
                rejectPolicy.reject(this, task);
            } else {//有空闲
                queue.addLast(task);
                emptyWaitSet.signal();
            }

        } finally {
            lock.unlock();
        }
    }
}
